package com.sunrate.investingquote.util;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author yyh
 * @description:
 * @date 2023/07/04/ 16:27
 */
public class ClassUtils {
    public static <R, T> List<R> getSonInstance(Class<T> fatherClass, Function<Class<T>, R> function) {
        //定义一个这回值
        List<Class<T>> returnlassList = getSonClass(fatherClass);
        return returnlassList.stream().map(function).collect(Collectors.toList());
    }

    public static <T> List<T> getSonInstance(Class<T> fatherClass) {
        //定义一个这回值
        return getSonClass(fatherClass).stream().map(o -> {
            T t;
            try {
                t = o.newInstance();
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
            return t;
        }).collect(Collectors.toList());
    }

    //根据父类查找到所有的手类，既认情况是子类和父类都在同一个包名下
    public static <T> List<Class<T>> getSonClass(Class<T> fatherClass) {
        //定义一个这回值
        List<Class<T>> returnlassList = new ArrayList<>();//获得也名你
        String packageName = fatherClass.getPackage().getName();//获得包中的所有类
        List<Class<T>> packClasses = getClasses(packageName);//判断是否是子类
        for (Class<T> c : packClasses) {
            if (fatherClass.isAssignableFrom(c) && !fatherClass.equals(c)) {
                returnlassList.add(c);
            }
        }

        return returnlassList;
    }

    //从一个包中意找出所有的类，在jar包中不能查找
    private static <T> List<Class<T>> getClasses(String packageName) {

        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        String path = packageName.replace(".", "/");
        Enumeration<URL> resources = null;
        try {
            resources = classLoader.getResources(path);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        List<File> dirs = new ArrayList<>();
        while (resources.hasMoreElements()) {
            URL resource = resources.nextElement();
            dirs.add(new File(resource.getFile()));
        }
        List<Class<T>> classes = new ArrayList<>();
        for (File directory : dirs) {
            classes.addAll(findClasses(directory, packageName));
        }
        return classes;
    }

    private static <T> List<Class<T>> findClasses(File directory, String packageNane) {
        List<Class<T>> classes = new ArrayList<>();
        if (!directory.exists()) {
            return classes;
        }

        File[] files = directory.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                assert !file.getName().contains(".");
                classes.addAll(findClasses(file, packageNane + "." + file.getName()));
            } else if (file.getName().endsWith(".class")) {
                try {
                    classes.add((Class<T>) Class.forName(packageNane + "." + file.getName().substring(0, file.getName().length() - 6)));
                } catch (ClassNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }

        }
        return classes;
    }
}